#include "EditSheet.h"

#include <DndData/CharacterRecord.h>

#include <QDialogButtonBox>
#include <QScrollArea>
#include <QVBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QSpinBox>
#include <QMetaObject>
#include <QMetaProperty>
#include <QHBoxLayout>
#include <QList>
#include <QTimer>
#include <QDebug>

struct TargetData
{
    TargetData() : prop(0), label(0) {}
    const char *prop;
    QLabel *label;
};

EditSheet::EditSheet(CharacterRecord *record, QWidget *parent)
    : QDialog(parent)
    , mRecord(record)
    , mScroll(new QScrollArea(this))
    , mTarget(0)
{
    setWindowTitle(tr("Character Sheet Property Editor"));
    QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok
                                      | QDialogButtonBox::Cancel);

    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->addWidget(mScroll);
    layout->addWidget(buttonBox);

    connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
    connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
    QTimer::singleShot(0, this, SLOT(initPropertyEditor()));
}

void EditSheet::initPropertyEditor()
{
    QVBoxLayout *layout = new QVBoxLayout();
    QWidget *w; QLineEdit *le; QSpinBox *sp;
    QVariant var;
    int prop = 0;
    bool ok;
    qDebug() << "EditSheet::initPropertyEditor - mRecord:" << mRecord;
    const QMetaObject* metaObject = mRecord->metaObject();
    qDebug() << "EditSheet::initPropertyEditor - mRecord:" << metaObject;
    int start = metaObject->propertyOffset();
    int count = metaObject->propertyCount();
    for (int i = start; i < count; ++prop, ++i)
    {
        QMetaProperty propDesc = metaObject->property(i);
        Q_ASSERT(propDesc.isValid());
        QFrame *frame = new QFrame(this);
        frame->setStyleSheet(prop % 2 ? "background: grey;" : "background: white;");
        QHBoxLayout *frameLayout = new QHBoxLayout();
        QLabel *label = new QLabel(propDesc.name());
        frameLayout->addWidget(label);
        var = mRecord->property(propDesc.name());
        Q_ASSERT(var.isValid());
        if (propDesc.isWritable())
        {
            switch (propDesc.type())
            {
                case QVariant::String:
                    le = new QLineEdit(var.toString());
                    connect(le, SIGNAL(textChanged(QString)), this, SLOT(textChanged(QString)));
                    w = le;
                    break;
                case QVariant::Int:
                    sp = new QSpinBox();
                    sp->setValue(var.toInt(&ok));
                    Q_ASSERT(ok);
                    connect(sp, SIGNAL(valueChanged(int)), this, SLOT(valueChanged(int)));
                    w = sp;
                    break;
                default:
                    qWarning() << "Unhandled prop type" << propDesc.typeName();
                    continue;
            }
            mWidgetToPropMap[w].prop = propDesc.name();
        }
        else
        {
            w = new QLabel(var.toString());
        }
        frameLayout->addWidget(w);
        frame->setLayout(frameLayout);
        layout->addWidget(frame);
    }
    w = new QWidget();
    w->setMinimumSize(300, 800);
    w->setLayout(layout);
    mScroll->setWidget(w);
}

EditSheet::~EditSheet()
{
    delete mScroll;
}

void EditSheet::updateTargetLabel(QWidget *src, const QString &text, const char *prop)
{
    QLabel *label = 0;
    QVariant var;
    label = mWidgetToPropMap[src].label;
    if (!label)
    {
        QList<QLabel *> list = mTarget->findChildren<QLabel *>();
        QList<QLabel *>::iterator it = list.begin();
        for ( ; it != list.end(); ++it)
        {
            var = (*it)->property("sourceProperty");
            if (var.isValid() && var.toString() == prop)
                break;
        }
        if (it == list.end())
        {
            qWarning() << "Failed to find property in UI sheet:" << prop;
            return;
        }
        label = *it;
        mWidgetToPropMap[src].label = label;
    }
    label->setText(text);
}

void EditSheet::textChanged(const QString &text)
{
    QWidget *src = qobject_cast<QWidget*>(sender());
    Q_ASSERT(src);
    Q_ASSERT(mWidgetToPropMap.contains(src));
    const char *prop = mWidgetToPropMap[src].prop;
    mRecord->setProperty(prop, QVariant(text));
    if (mTarget)
        updateTargetLabel(src, text, prop);
}

void EditSheet::valueChanged(int value)
{
    QWidget *src = qobject_cast<QWidget*>(sender());
    Q_ASSERT(src);
    Q_ASSERT(mWidgetToPropMap.contains(src));
    const char *prop = mWidgetToPropMap[src].prop;
    mRecord->setProperty(prop, QVariant(value));
    if (mTarget)
        updateTargetLabel(src, QString::number(value), prop);
}
